import cgi
import datetime
import hashlib
import hmac
import base64
import wsgiref.handlers

from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp

from urllib import urlencode

class Callable:
    def __init__(self, anycallable):
        self.__call__ = anycallable

class AllowSite(db.Model):
    site_name = db.StringProperty()
    site_url = db.LinkProperty()
      
class GameChart(db.Model):
    user_name = db.StringProperty()
    user_id = db.StringProperty()
    user_link = db.LinkProperty()
    user_image = db.LinkProperty()
    user_large_image = db.LinkProperty()
    platform = db.StringProperty()
    score = db.IntegerProperty()
    create_date = db.DateTimeProperty(auto_now_add=True)
    chart_id = db.IntegerProperty()
    chart_name = db.StringProperty()
    
    def array_to_XML(game_chart):
        xml_data = ""
        xml_data += ("<?xml version=\"1.0\" encoding=\"utf-8\" ?>")
        xml_data += ("<GameChart>")
        for chart_iterator in game_chart:
           child_node = "<Chart>"
           child_node += ('<user_id>' + cgi.escape(chart_iterator.user_id) + '</user_id>' )
           child_node += ('<user_name>' + cgi.escape(chart_iterator.user_name) + '</user_name>' )
           child_node += ('<user_link>' + cgi.escape(chart_iterator.user_link) + '</user_link>' )
           child_node += ('<user_image>' + cgi.escape(chart_iterator.user_image) + '</user_image>' )
           child_node += ('<user_large_image>' + cgi.escape(chart_iterator.user_large_image) + '</user_large_image>' )
           child_node += ('<platform>' + cgi.escape(chart_iterator.platform) + '</platform>' )
           child_node += ('<score>' + cgi.escape(str(chart_iterator.score)) + '</score>' )
           #xml_data += ('<create_date>' + cgi.escape(str(chart_iterator.create_date)) + '</create_date>' )
           child_node += "</Chart>"
           xml_data += child_node
           
        xml_data += ("</GameChart>")
        return xml_data
    array_to_XML = Callable(array_to_XML)    
class CrossDomain(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/xml'
        allow_site = db.GqlQuery("SELECT * FROM AllowSite")
       
        xml_data = ""
        xml_data += ("<?xml version=\"1.0\" encoding=\"utf-8\" ?>")
        xml_data += ("<cross-domain-policy>")
        for xml_iterator in allow_site:
            xml_data += ("<allow-access-from domain=\"" + cgi.escape(xml_iterator.site_url) + "\"/>")
        xml_data += ("</cross-domain-policy>")
    
        self.response.out.write(xml_data)   
class DefaultPage(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/xml'
        game_chart = db.GqlQuery("SELECT * FROM GameChart ORDER BY create_date DESC LIMIT 10")
        
        self.response.out.write(GameChart.array_to_XML(game_chart))

class SignatureMethod_HMAC_SHA1():
    def get_name(self):
        return 'HMAC-SHA1'
    
    def get_key(self):
        return "http://www.moorwind.com/HMAC_SHA1"
        
    def build_signature_base_string(self, chart_request):
        raw = ""
        
        raw += urlencode({'user_name' : chart_request.request.get("user_name")})
        raw += "&" + urlencode({'user_id' : chart_request.request.get("user_id")})
        raw += "&" + urlencode({'user_link' : chart_request.request.get("user_link")})
        raw += "&" + urlencode({'user_image' : chart_request.request.get("user_image")})
        raw += "&" + urlencode({'user_large_image' : chart_request.request.get("user_large_image")})
        raw += "&" + urlencode({'platform' : chart_request.request.get("platform")})
        raw += "&" + urlencode({'score' : chart_request.request.get("score")})
        raw += "&" + urlencode({'chart_id' : chart_request.request.get("chart_id")})
        raw += "&" + urlencode({'chart_name' : chart_request.request.get("chart_name")})
        
        return raw

    def build_signature(self, chart_request):       
        raw = self.build_signature_base_string(chart_request)
        key = self.get_key()

        hashed = hmac.new(key, raw, hashlib.sha1)

        return base64.b64encode(hashed.digest())
    
    def compure_signature(self, chart_request):
        signature_custom = chart_request.request.get("signature")
        signature_build = self.build_signature(chart_request)
        return signature_custom == signature_build

class ErrorMessage():
    def get_null_param(self):
        return "lack of params"
    def get_error_signature(self):
        return "error signature"

class TokenService(webapp.RequestHandler):
    def get(self):
        hmac_sha1 = SignatureMethod_HMAC_SHA1()
        self.response.headers['Content-Type'] = 'text/xml'
        self.response.out.write("<?xml version=\"1.0\" encoding=\"utf-8\" ?>")
        self.response.out.write("<token><![CDATA[")
        self.response.out.write(cgi.escape(hmac_sha1.get_key()))
        self.response.out.write("]]></token>")

class ChartService(webapp.RequestHandler):
    def check_request(self):
        if self.request.get("user_name") == "":
            return False
        if self.request.get("user_id") == "":
            return False
        if self.request.get("user_link") == "":
            return False
        if self.request.get("user_image") == "":
            return False
        if self.request.get("user_large_image") == "":
            return False
        if self.request.get("platform") == "":
            return False
        if self.request.get("score") == "":
            return False
        if self.request.get("chart_id") == "":
            return False
        if self.request.get("chart_name") == "":
            return False
        if self.request.get("signature") == "":
            return False
        return True
    
    def show_error_message(self, message):
        msg = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
        msg += "<error><isError>true</isError><message>"
        msg += cgi.escape(message)
        msg += "</message></error>"
        self.response.out.write(msg)
      
    def get(self):        
        chart_id = int(self.request.get("chart_id"))
        game_chart = db.GqlQuery("SELECT * FROM GameChart WHERE chart_id=:1 ORDER BY create_date DESC LIMIT 10", chart_id)
        
        self.response.headers['Content-Type'] = 'text/xml'
        self.response.out.write(GameChart.array_to_XML(game_chart))
        
    def post(self):        
        game_chart = GameChart()
        self.response.headers['Content-Type'] = 'text/xml'
        emsg = ErrorMessage()
        
        if self.check_request():            
            game_chart.user_name = self.request.get("user_name")
            game_chart.user_id = self.request.get("user_id")
            game_chart.user_link = self.request.get("user_link")
            game_chart.user_image = self.request.get("user_image")
            game_chart.user_large_image = self.request.get("user_large_image")
            game_chart.platform = self.request.get("platform")
            game_chart.score = int(self.request.get("score"))
            game_chart.chart_id = int(self.request.get("chart_id"))
            game_chart.chart_name = self.request.get("chart_name")
        
            hmac_sha1 = SignatureMethod_HMAC_SHA1()
            
            if hmac_sha1.compure_signature(self):
                game_chart.put()
            else:
                self.show_error_message(emsg.get_error_signature())
        
            new_chart_id = int(self.request.get("chart_id"))
            new_game_chart = db.GqlQuery("SELECT * FROM GameChart WHERE chart_id=:1 ORDER BY create_date DESC LIMIT 10", new_chart_id)
            
            self.response.out.write(GameChart.array_to_XML(new_game_chart))   
                    
        else:                 
            self.show_error_message(emsg.get_null_param())
        
application = webapp.WSGIApplication([
  ('/', DefaultPage),
  ('/token_service.py', TokenService),
  ('/crossdomain.xml', CrossDomain),
  ('/chart_service.py', ChartService)
], debug=True)


def main():
  wsgiref.handlers.CGIHandler().run(application)


if __name__ == '__main__':
  main()
